﻿module tweetc.Console

open System
open System.Collections.Generic
open System.IO
open System.Net
open System.Globalization
open System.Text.RegularExpressions
open tweetc.Utilities
open tweetc.ApplicationSettings
open tweetc.OAuth
open tweetc.TweetStatus

let settings = new ApplicationSettings()

let getCredentials() =
    if String.IsNullOrWhiteSpace settings.OAuthToken || 
        String.IsNullOrWhiteSpace settings.OAuthTokenSecret then
        let token, secret, confirmed = requestToken()
        let url = authorizeURI + "?oauth_token=" + token
        System.Diagnostics.Process.Start("iexplore.exe", url) |> ignore

        let welcome = [
            "Welcome to tweetc, your windows command line twitter client"
            "First, we need to get a PIN from twitter to authorize tweetc"
            "to use your account."
            ""
            "tweetc will launch a browser window to access your account"
            "After logging in, twitter will display a 7 digit PIN."
            ""]
        display welcome

        printf "Enter the PIN from the web page (PINs cannot be reused): "
        let pin = Console.ReadLine();

        let token, secret = accessToken token secret pin
        settings.OAuthToken <- token
        settings.OAuthTokenSecret <- secret
        settings.Save()
        printfn "OK, tweetc is ready to go now."

let showWaitProgress (task:Threading.Tasks.Task<string>) =
    while task.Wait(200) = false do printf "."
    printfn ""
    
let getAsync url queryParameters =
    async {
        System.Net.ServicePointManager.Expect100Continue <- false
        let data = queryParameters |> convertToQueryString
        let request = WebRequest.Create(url + "?" + data, Method="GET")
        request.AddOAuthHeader(settings.OAuthToken, settings.OAuthTokenSecret, queryParameters)
        use reader = new StreamReader(request.GetResponse().GetResponseStream())
        return reader.ReadToEnd()
    }

let get url queryParameters =
    let task = Async.StartAsTask(getAsync url queryParameters)
    showWaitProgress task
    task.Result

let postAsync (url:string) queryParameters =
    async {
        System.Net.ServicePointManager.Expect100Continue <- false
        let request = WebRequest.Create(url, Method="POST")
        request.AddOAuthHeader(settings.OAuthToken, settings.OAuthTokenSecret, queryParameters)
        let bodyWriter = new StreamWriter(request.GetRequestStream())
        bodyWriter.Write(convertToQueryString queryParameters)
        bodyWriter.Close()
        use reader = new StreamReader(request.GetResponse().GetResponseStream())
        return reader.ReadToEnd()
    }

let post url queryParameters =
    let task = Async.StartAsTask(postAsync url queryParameters)
    showWaitProgress task
    task.Result

let showItem id name screenName (date:DateTime) text =
    cprintf settings.SeparatorColor "%s\n\n" (new String('\xAF', 79))
    cprintf settings.TextColor "%-21s" name
    text |> wrap 58 |> List.iter (fun t -> cprintf settings.TextColor "%s\n%21s" t "")
    let indexTime = sprintf "%s %3s" screenName (relativeTime date)
    cprintf settings.SeparatorColor "%58s\n" indexTime
    cprintf settings.SeparatorColor "%79s\n" id

let showTweets json =
    let showTweet (tweet:Tweet) =
        let user = if obj.ReferenceEquals(tweet.User, Unchecked.defaultof<_>)
                       then tweet.Sender
                       else tweet.User
        showItem tweet.Id user.Name ("@" + user.ScreenName) (toDateTime tweet.DateStr) tweet.Text
    let tweets = Array.rev (parseTweets json)
    Array.iter showTweet tweets

let home (count:int) =
    let json = get "https://api.twitter.com/1/statuses/home_timeline.json" ["count", string count]
    showTweets json

let mentions (count:int) =
    let json = get "http://api.twitter.com/1/statuses/mentions.json" ["count", string count]
    showTweets json

let messages (count:int) =
    let json = get "http://twitter.com/direct_messages.json" ["count", string count]
    showTweets json

let showSearchResults results =
    let showResult (result:SearchResult) =
        showItem result.Id result.Name "" (DateTime.Parse(result.DateStr)) result.Text
    let search = parseSearch results
    Array.iter showResult (Array.rev search.Results)

let search (count:int) query =
    let json = get "https://search.twitter.com/search.json" [("rpp", string count);("q", string query)]
    showSearchResults json

let updateHome text =
    post "https://api.twitter.com/1/statuses/update.json" ["status", text]

let clearAllSettings() =
    settings.ClearAllSettings()

let (|Option|_|) option input =
    let m = Regex.Match(input, option + "([0-9]+)")
    if m.Success then Some(int m.Groups.[1].Value)
    elif input = option then Some(20)
    else None 

let processArgs (args:string[]) =
    if args.Length = 0 
    then getCredentials(); home 10
    else match args.[0] with
         | "-?"
         | "-help"           -> showHelp()
         | "-reset"          -> clearAllSettings()
         | Option "-h" count -> getCredentials(); home count   
         | Option "-m" count -> getCredentials(); mentions count 
         | Option "-d" count -> getCredentials(); messages count 
         | Option "-s" count -> search count (String.Join(" ", Array.sub args 1 (args.Length - 1)))
         | _                 -> getCredentials(); updateHome (String.Join(" ", args)) |> ignore

[<EntryPoint>]
let main (args:string[]) =
    try
        Console.CursorVisible <- false
        processArgs args
        0
    finally
        Console.ResetColor()
        Console.CursorVisible <- true